<?php

class users extends meccanoFilters
{

   private $logedstatus       = FALSE;
   private $timeout           = 0;
   private $autologin_timeout = 0;
   private $users             = array();
   private $groups            = array();
   private $roles             = array();
   private $filters           = array();

   
   public function  __construct()
   {
      parent::__construct();
      $this->setFilter(FALSE);

      paginator::setCurrentPage(1, 'users');
      paginator::setItemsOnPage(config::read('items'), 'users');
   }


   /**
    * Set filter for selecting User
    *
    * @param array $set
    * @return bool
    */
   private function setFilter($set = FALSE)
   {
      if(empty($set))
      {
         $this->clearFilter();
         return FALSE;
      }

      # RULES FOR ALLOWED SETS
      // TODO: добавить метод установки сортировки, добавить функционал сортровки

      $allowed_sets['u'] = array(
          'id' => 'Integer',
          'login' => 'Alpha',
          'email' => 'Email',
          'active' => 'Integer');
      $allowed_sets['g'] = array(
          'gid' => 'Integer');
      $allowed_sets['r'] = array(
          'id' => 'Integer',
          'role' => 'Alpha');

      $filters = array();
      $from    = array();


      foreach ($set AS $t => $s)
      {
         if (isset($allowed_sets[$t]))
         {
            foreach ($s AS $k => $v)
            {
               if (isset($allowed_sets[$t][$k]))
               {
                  if ($allowed_sets[$t][$k])
                  {
                     if(is_array($v))
                     {
                        $filter_method = 'filterFor'. $allowed_sets[$t][$k];
                     } else
                     {
                        $filter_method = 'isValid'. $allowed_sets[$t][$k];
                     }

                     if(is_array($v))
                     {
                        $v = $this->$filter_method($v);
                        if(!empty($v))
                        {
                           foreach($v AS $test_key=>$test_value)
                           {
                              $v[$test_key] = $this->ClearHtml($test_value);
                           }
                           $filters[] = '`'. $t .'`.`'. $k .'` IN ("'. implode('","',  $v) .'")';
                        }
                     } elseif ($this->$filter_method($v))
                     {
                        $filters[] = '`' . $t . '`.`' . $k . '` = "' . $this->ClearHtml($v) . '"';
                     }
                  } else
                  {
                     $filters[] = '`' . $t . '`.`' . $k . '` = "' . $this->ClearHtml($v) . '"';
                  }
               }
            }

            switch($t)
            {
               case 'g':
                  if(empty($from['g']))
                  {
                     $from['g'] = '`meccano_user2group` AS `g`';
                     $filters[] = '`g`.`uid` = `u`.`id`';
                  }
            }
         }

         # COMPILE FILTER CONDITIONS
         if(!empty($filters))
         {
            $this->filters['where'] .= ($this->filters['where'] ? ' AND ' : 'WHERE '). implode(' AND ', $filters);
         }
      }

      if(!empty($from))
      {
         $this->filters['from'] .= ', '. implode(', ', $from);
      }
   }


   /**
    * Clear Filter SQL for Queries
    */
   private function clearFilter()
   {
      $this->filters['from'] = 'FROM `meccano_users` AS `u`';
      $this->filters['where'] = session::user('id') != 1 ? 'WHERE `u`.`id` > 1' : '';
   }
   

   /**
    * Get array of Users
    *
    * @param array $set
    * @param bool $getall
    * @return array
    */
   public function getUsers($set = NULL, $getall = FALSE)
   {
      if(!empty($set))
         $this->setFilter($set);
      elseif($set === FALSE)
         $this->setFilter();

      $DB = database::getInstance();

      $sql = 'SELECT ';
      if (!$getall)
         $sql .= ' SQL_CALC_FOUND_ROWS ';
      $sql .= ' `u`.* ' . $this->filters['from'] . $this->filters['where'];
      if (!$getall)
         $sql .= ' LIMIT ' . ((paginator::getCurrentPage('users') - 1) * paginator::getItemsOnPage('users')) . ', ' . paginator::getItemsOnPage('users');

      $data = array();
      $DB->sql = $sql;
      $DB->DB_Fetch();
      for ($i = 0, $t = $DB->rows; $i < $t; $i++)
      {
         $user = new user();
         $user->loadFromArray($DB->fetched[$i]);
         $data[$user->id] = $user;
      }

      # GET ALL GROUPS BY ALL USERS
      if(!empty($data))
      {
         $uids = array_keys($data);
         $DB->sql = 'SELECT meccano_user2group.uid, meccano_groups.group
            FROM meccano_groups, meccano_user2group
            WHERE meccano_groups.id = meccano_user2group.gid
            AND meccano_user2group.uid IN ('. implode(',', $uids) .')
            ORDER BY meccano_groups.group ASC';
         $DB->DB_Fetch();
         
         $u_groups = array();
         for($i=0, $t=$DB->rows; $i<$t; $i++)
         {
            $u_groups[$DB->fetched[$i]['uid']][] = $DB->fetched[$i]['group'];
         }

         foreach($data AS $k=>$v)
         {
            if(!empty($u_groups[$k]))
            {
               $data[$k]->groupsByString = implode(', ', $u_groups[$k]);
            }
         }
      }

      # SET PAGES
      if (!$getall)
      {
         $DB->sql = 'SELECT FOUND_ROWS()';
         $tmp = $DB->DB_FetchFlat();
         $tmp = reset($tmp);
         paginator::setPages($tmp, 'users');
      }

      $this->clearFilter();
      $this->users = $this->users + $data;

      return $data;
   }


   /**
    * Turn Account On
    * @param integer $id
    */
   public function turnOnUser($id)
   {
      if (!$this->isValidInteger($id))
         return FALSE;

      $DB = database::getInstance();
      $DB->sql = 'UPDATE `meccano_users` SET `active` = "1", `key` = NULL WHERE `id` = ' . $id;
      return $DB->DB_Query();
   }

   /**
    * Turn Account Off
    * @param integer $id
    */
   public function turnOffUser($id)
   {
      if (!$this->isValidInteger($id))
         return FALSE;

      $DB = database::getInstance();
      $DB->sql = 'UPDATE `meccano_users` SET `active` = "0" WHERE `id` = ' . $id;
      return $DB->DB_Query();
   }


   public function deleteUser($ids)
   {
      $ids = array_filter($ids, 'is_numeric');
      if(!empty($ids) && session::user() && session::user()->hasRole('ADMIN'))
      {
         $users = $this->getUsers(array('u'=>array('id'=>$ids)), TRUE);
         if(!empty($users))
         {
            foreach($users AS $u)
            {
               $u->delete();
            }

            $DB = database::getInstance();
            $DB->sql = 'DELETE FROM `meccano_users` WHERE `id` IN ('. join(',', $ids) .')';
            $DB->DB_Query();
            $DB->sql = 'DELETE FROM `meccano_user2group` WHERE `uid` IN ('. join(',', $ids) .')';
            $DB->DB_Query();

            return TRUE;
         }
      }

      return FALSE;
   }

   

   /**
    * Get array of groups
    *
    * @return array
    */
   public function getGroups()
   {
      if (!empty($this->groups))
         return $this->groups;

      $DB = database::getInstance();

      # GET ASSIGNED ROLES
      $DB->sql = 'SELECT `t1`.`gid`, `t2`.* FROM `meccano_role2group` AS `t1`, `meccano_roles` AS `t2` WHERE `t1`.`rid` = `t2`.`id`';
      $DB->DB_Fetch();
      $roles_matrix = array();
      for($i=0, $t = $DB->rows; $i< $t; $i++)
      {
         $r = $DB->fetched[$i];
         $roles_matrix[$r['gid']][$r['id']] = $r['role'];
      }

      $DB->sql = 'SELECT * FROM `meccano_groups`';
      $DB->DB_Fetch();
      $groups = array();
      for ($i = 0, $t = $DB->rows; $i < $t; $i++)
      {
         $g = $DB->fetched[$i];
         $groups[$g['id']] = $g;
         $groups[$g['id']]['roles'] = isset($roles_matrix[$g['id']]) ? array_values($roles_matrix[$g['id']]) : array();
      }
      
      $this->groups = $groups;

      return (empty($groups) ? FALSE : $groups);
   }


   /**
    * Get Group by ID
    *
    * @param integer $id
    * @return array
    */
   public function getGroup($id)
   {
      if (!$this->isValidInteger($id))
         return FALSE;

      if (isset($this->groups[$id]))
         return $this->groups[$id];

      $DB = database::getInstance();
      $DB->sql = 'SELECT `t1`.*, `t3`.`role` FROM `meccano_groups` AS `t1`, `meccano_role2group` AS `t2`, `meccano_roles` AS `t3` WHERE `t1`.`id` = `t2`.`gid` AND `t2`.`rid` = `t3`.`id` AND `t1`.`id` = ' . $id;
      $DB->DB_Fetch();

      $group = array();
      for ($i = 0, $t = $DB->rows; $i < $t; $i++)
      {
         if ($i == 0)
         {
            $group['id']    = $DB->fetched[$i]['id'];
            $group['group'] = $DB->fetched[$i]['group'];
            $group['descr'] = $DB->fetched[$i]['descr'];
         }
         $group['roles'][] = $DB->fetched[$i]['role'];
      }

      return $group;
   }


   /**
    * Update Group
    *
    * @param array $params
    */
   public function updateGroup($id, $params)
   {
      if (empty($params['group']) || empty($params['descr']))
      {
         $this->ERROR->setError(
                 array(
                     'code' => 'validateInput',
                     'varkey' => 'required_fields'
                 )
         );
      }

      $DB = database::getInstance();
      $DB->DB_QueryBuilder('UPDATE `meccano_groups` SET `group` = "%s", `descr` = "%s" WHERE `id` = %i', array($params['group'], $params['descr'], $id));
      $DB->DB_Query();
      if(!empty($params['role']))
      {
         $this->updateGroupRoles($id, $params['role']);
      }
   }


   /**
    * Add new Group
    *
    * @param array $params
    */
   public function addGroup($params)
   {
      if (empty($params['group']) || empty($params['descr']))
      {
         $this->ERROR->setError(
                 array(
                     'code' => 'validateInput',
                     'varkey' => 'required_fields'
                 )
         );
      }

      $DB = database::getInstance();

      $DB->DB_QueryBuilder('INSERT INTO `meccano_groups` (`group`, `descr`) VALUES ("%s", "%s")', array($params['group'], $params['descr']));
      $DB->DB_Query();
      if(!empty($params['role']))
      {
         $this->updateGroupRoles($DB->DB_LastID(), $params['role']);
      }
   }
   

   /**
    * Get array of Roles
    *
    * @return array
    */
   public function getRoles()
   {
      if (!empty($this->roles))
         return $this->roles;

      $DB     = database::getInstance();

      $DB->sql = 'SELECT * FROM `meccano_roles` ORDER BY `role`';
      $DB->DB_Fetch();

      $roles = array();
      for ($i = 0; $i < $DB->rows; $i++)
      {
         $roles[$DB->fetched[$i]['id']]['id']    = $DB->fetched[$i]['id'];
         $roles[$DB->fetched[$i]['id']]['role']  = $DB->fetched[$i]['role'];
         $roles[$DB->fetched[$i]['id']]['descr'] = gettext::translate('roles', $DB->fetched[$i]['role']);
      }

      $this->roles = $roles;

      return $roles;
   }



   /**
    * Update Roles assigned to group
    *
    * @param integer $id
    * @param array $roles
    */
   private function updateGroupRoles($id, $roles)
   {
      if (!$this->isValidInteger($id))
         return FALSE;
      if (!is_array($roles))
         return FALSE;

      $roles_exist = @array_keys($this->getRoles());
      $roles = array_intersect($roles_exist, $roles);
      $roles = array_values($roles);

      $DB = database::getInstance();

      if(!empty($roles))
      {
         $DB->sql = 'DELETE FROM `meccano_role2group` WHERE `gid` = '. $id;
         $DB->DB_Query();

         $sql_vars = array();
         for($i=0, $t=count($roles); $i<$t; $i++)
         {
            $sql_vars[] = '('. $id .', '. $roles[$i] .')';
         }
         if(!empty($sql_vars))
         {
            $DB->sql = 'INSERT INTO `meccano_role2group` (`gid`, `rid`) VALUES '. implode(',', $sql_vars);
            $DB->DB_Query();
         }
      }
   }
}